from PyQt5 import uic
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import pyqtgraph as pg
from ga_algorithm import *
import xlrd
from threading import Thread, RLock
from ChildrenWindows import *
from multiprocessing import Process
from queue import Queue


class VRP_Algorithm(object):
    def __init__(self, paras):
        self.algorithm = GA(paras)


class MySignal(QObject):
    textbro_printer = pyqtSignal(QPlainTextEdit, str)
    textedt_printer = pyqtSignal(QPlainTextEdit, str)


class Main_App(QMainWindow):

    def __init__(self, *args, **kwargs):
        self.RunningGAObject = None
        self.mysignal = MySignal()
        self.threadLock = RLock()
        # 从文件中加载UI定义
        super().__init__(*args, **kwargs)
        self.params = {}
        """设置各个参数的实体"""
        """组件一参数"""
        # 坐标图信息
        self.params['NodesLocation'] = []  # 必填
        data = xlrd.open_workbook('Location.xlsx')
        location = data.sheets()[0]
        for value in range(0, location.nrows):
            Loc = (float(location.row_values(value)[0]), float(location.row_values(value)[1]))
            self.params['NodesLocation'].append(Loc)
        # 需求表，将配送中心的需求设置为0
        self.params['NodesDemand'] = []  # 必填
        for value in range(0, location.nrows):
            demand = float(location.row_values(value)[2])
            self.params['NodesDemand'].append(demand)
        """组件二参数"""
        """组件三参数"""
        self.params['CarIsChangeAble'] = None
        self.params['CarIsNotChangeAble'] = None  # 以上两个二选一
        self.params['CarNumSet'] = 0  # CarIsNotChangeAble = True 时，需要填写，否则设为不可编辑（灰色）
        self.params['OneTypeCar'] = False
        self.params['TwoTypeCar'] = False  # 以上两个二选一
        self.params['Load_1'] = 0
        self.params['Load_2'] = 0  # TwoTypeCar = True 时，需要填写，否则设为不可编辑（灰色）
        self.params['CarSpeed'] = 0  # 必填
        """组件四参数"""
        self.params['UnloadTime'] = 0  # 必填
        """组件五参数"""
        self.params['TimeLimit'] = 0  # 必填
        """组件六参数"""
        self.params['LengthLimit'] = 0  # 必填
        """组件七参数"""
        self.params['GenerationsNumber'] = 400  # 必填
        """传递初始参数"""
        self.VRPAlgorithm1 = VRP_Algorithm(self.params)
        """初始化各个窗口"""
        self.UnloadTime = Ui_UnloadTime()
        self.CarInfo = Ui_CarInfo(self.params)
        self.TimeLimit = Ui_TimeLimit()
        self.LengthLimit = Ui_LengthLimit()
        self.NetInfo = Ui_NetInfo()

        self.MainWindow_Ui = uic.loadUi("Main_Frame.ui")

        self.pos1 = []
        for i in range(0, len(self.params['NodesLocation'])):
            self.pos1.append([self.params['NodesLocation'][i][0], self.params['NodesLocation'][i][1]])
        self.pos = np.array(self.pos1)

        """加载各个窗口"""
        self.initUi()

    def Main_Algorithm_Thread1(self):
        self.RunningGAObject.GAProcess()

    def printToGUI1(self, fb, text):
        fb.appendPlainText(str(text))
        fb.ensureCursorVisible()

    def printToGUI2(self, fb, text):
        fb.setPlainText(str(text))
        fb.ensureCursorVisible()

    def AppendLogbook(self):
        def run():
            while True:
                self.mysignal.textbro_printer.emit(self.MainWindow_Ui.EvolutionProcess1,
                                                   self.RunningGAObject.EvolutionQueue.get())
                temp = self.RunningGAObject.PopulationDeliver.get()
                population = ''
                for i in range(0, len(temp)):
                    population += 'individual:' + str(i + 1) + '\n' + str(temp[i]) + '\n'
                self.mysignal.textedt_printer.emit(self.MainWindow_Ui.Population,
                                                   population)

        AppendLogbookThread = Thread(target=run)
        AppendLogbookThread.start()

    def AppendFinalRouting(self):
        def run():
            while True:
                self.mysignal.textbro_printer.emit(self.MainWindow_Ui.GAProcessing,
                                                   self.RunningGAObject.FinalOutput.get())

        AppendFinalRoutingThread = Thread(target=run)
        AppendFinalRoutingThread.start()

    def Draw(self):
        def run():
            threadLock.acquire()
            while True:
                threadLock.acquire()
                avg = self.RunningGAObject.AVGDeliver.get()
                bst = self.RunningGAObject.BestDeliver.get()
                # draw the function
                x_ = []
                for i in range(0, len(avg)):
                    x_.append(i + 1)
                self.MainWindow_Ui.Status.plot(x_, avg)
                self.MainWindow_Ui.Status.plot(x_, bst)

                BestInvidual = self.RunningGAObject.BestIndividual.get()
                individual1 = []
                for i in range(0, len(BestInvidual) - 1):
                    individual1.append([BestInvidual[i], BestInvidual[i + 1]])
                individual = np.array(individual1)
                g = pg.GraphItem()
                symbols = []
                for i in range(0, len(self.pos)):
                    symbols.append('o')
                lines1 = []
                for i in range(0, len(individual1)):
                    lines1.append([255, 0, 0, 255, 1])
                lines = np.array(lines1)
                self.MainWindow_Ui.Map.clear()
                g.setData(pos=self.pos, adj=individual, pen=lines, size=1, symbol=symbols, pxMode=False)
                self.MainWindow_Ui.Map.addItem(g)
                threadLock.release()
            self.MainWindow_Ui.Start.setEnabled(True)
            threadLock.release()

        t = Thread(target=run)
        t.start()

    def Main_Algorithm(self):
        self.MainWindow_Ui.Start.setEnabled(False)
        self.RunningGAObject = self.VRPAlgorithm1.algorithm
        self.MainWindow_Ui.Map.clear()
        self.MainWindow_Ui.Status.clear()
        self.MainWindow_Ui.EvolutionProcess1.setPlainText('')
        self.MainWindow_Ui.Population.setPlainText('')
        self.VRPAlgorithm1.algorithm.dataDict['ngen'] = int(self.MainWindow_Ui.chooseGen.currentText())
        thread1 = threading.Thread(target=self.Main_Algorithm_Thread1, daemon=True, name='Main')
        thread2 = threading.Thread(target=self.AppendLogbook, daemon=True, name='EvoTxt')
        thread3 = threading.Thread(target=self.AppendFinalRouting, daemon=True, name='FinalRt')
        thread4 = threading.Thread(target=self.Draw, daemon=True, name='Draw')
        thread1.start()
        thread2.start()
        thread3.start()
        thread1.join()
        thread2.join()
        thread3.join()
        thread4.start()
        thread4.join()

    def initUi(self):
        self.MainWindow_Ui.Map.setTitle("交通图", color='008080', size='12pt')
        self.MainWindow_Ui.Map.setBackground('w')
        self.MainWindow_Ui.Map.showGrid(x=True, y=True)
        self.MainWindow_Ui.Map.setLabel("left", "y——坐标")
        self.MainWindow_Ui.Map.setLabel("bottom", "x——坐标")

        self.MainWindow_Ui.Status.setTitle("收敛表示", color='008080', size='12pt')
        self.MainWindow_Ui.Status.setBackground('w')
        self.MainWindow_Ui.Status.showGrid(x=True, y=True)
        self.MainWindow_Ui.Status.setLabel("left", "种群适应度")
        self.MainWindow_Ui.Status.setLabel("bottom", "进化代数")

        self.MainWindow_Ui.EvolutionProcess1.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.MainWindow_Ui.NetInfo.clicked.connect(lambda: self.open_NetInfo())  # 连接到打开网点数据表
        self.MainWindow_Ui.CarInfo.clicked.connect(lambda: self.open_CarInfo())  # 连接到打开车量设置界面
        self.MainWindow_Ui.UnloadTime.clicked.connect(lambda: self.open_UnloadTime())  # 连接到打开卸货时间设置界面
        self.MainWindow_Ui.TimeLimited.clicked.connect(lambda: self.open_TimeLimit())  # 连接到打开时间限制设置界面
        self.MainWindow_Ui.LengthLimited.clicked.connect(lambda: self.open_LengthLimit())  # 连接到打开距离限制设置界面
        self.MainWindow_Ui.Start.clicked.connect(lambda: self.Main_Algorithm())  # 连接到主算法
        self.mysignal.textbro_printer.connect(self.printToGUI1)
        self.mysignal.textedt_printer.connect(self.printToGUI2)

        self.MainWindow_Ui.isNetInfo.setVisible(False)
        self.MainWindow_Ui.isCarInfo.setVisible(False)
        self.MainWindow_Ui.isUnloadTime.setVisible(False)
        self.MainWindow_Ui.isTimeLimited.setVisible(False)
        self.MainWindow_Ui.isLengthLimited.setVisible(False)

    def open_NetInfo(self):
        self.NetInfo.location_demandTable_Ui.setWindowModality(Qt.ApplicationModal)
        self.NetInfo.location_demandTable_Ui.show()

    def open_CarInfo(self):
        """设置打开窗口的可视化值"""
        self.CarInfo.CarInfo_Ui.CarNum.setValue(self.CarInfo.CarInfoParams['CarNumSet'])
        self.CarInfo.CarInfo_Ui.Speed.setValue(self.CarInfo.CarInfoParams['CarSpeed'])

        """显示窗口"""
        self.CarInfo.CarInfo_Ui.setWindowModality(Qt.ApplicationModal)
        self.CarInfo.CarInfo_Ui.Ok.clicked.connect(lambda: self.deliver_CarInfo())
        self.CarInfo.CarInfo_Ui.show()

    def deliver_CarInfo(self):
        """传递参数"""
        self.params['CarIsChangeAble'] = self.CarInfo.CarInfoParams['CarIsChangeAble']
        self.params['CarIsNotChangeAble'] = self.CarInfo.CarInfoParams['CarIsNotChangeAble']
        self.params['CarNumSet'] = self.CarInfo.CarInfoParams['CarNumSet']
        self.params['OneTypeCar'] = self.CarInfo.CarInfoParams['OneTypeCar']
        self.params['TwoTypeCar'] = self.CarInfo.CarInfoParams['TwoTypeCar']
        self.params['Load_1'] = self.CarInfo.CarInfoParams['Load_1']
        self.params['Load_2'] = self.CarInfo.CarInfoParams['Load_2']
        self.params['CarSpeed'] = self.CarInfo.CarInfoParams['CarSpeed']

        self.VRPAlgorithm1.__init__(self.params)

    def open_UnloadTime(self):
        """设置打开窗口的可视化值"""
        self.UnloadTime.UnloadTime_Ui.UnloadTime.setValue(self.UnloadTime.UnloadTimePara)
        """打开窗口"""
        self.UnloadTime.UnloadTime_Ui.setWindowModality(Qt.ApplicationModal)
        self.UnloadTime.UnloadTime_Ui.Ok.clicked.connect(lambda: self.deliver_UnloadTime())
        self.UnloadTime.UnloadTime_Ui.show()

    def deliver_UnloadTime(self):
        """传递参数"""
        self.params['UnloadTime'] = self.UnloadTime.UnloadTimePara
        self.VRPAlgorithm1.__init__(self.params)

    def open_TimeLimit(self):
        """设置打开窗口的可视化值"""
        self.TimeLimit.TimeLimit_Ui.TimeLimit.setValue(self.TimeLimit.TimeLimitPara)
        """打开窗口"""
        self.TimeLimit.TimeLimit_Ui.setWindowModality(Qt.ApplicationModal)
        self.TimeLimit.TimeLimit_Ui.Ok.clicked.connect(lambda: self.deliver_TimeLimit())
        self.TimeLimit.TimeLimit_Ui.show()

    def deliver_TimeLimit(self):
        """传递参数"""
        self.params['TimeLimit'] = self.TimeLimit.TimeLimitPara
        self.VRPAlgorithm1.__init__(self.params)

    def open_LengthLimit(self):
        """设置打开窗口的可视化值"""
        self.LengthLimit.LengthLimit_Ui.LengthLimit.setValue(self.LengthLimit.LengthLimitPara)
        """打开窗口"""
        self.LengthLimit.LengthLimit_Ui.setWindowModality(Qt.ApplicationModal)
        self.LengthLimit.LengthLimit_Ui.Ok.clicked.connect(lambda: self.deliver_LengthLimit())
        self.LengthLimit.LengthLimit_Ui.show()

    def deliver_LengthLimit(self):
        """传递参数"""
        self.params['LengthLimit'] = self.LengthLimit.LengthLimitPara
        self.VRPAlgorithm1.__init__(self.params)


if __name__ == "__main__":
    app = QApplication([])
    MainWindow = Main_App()
    MainWindow.MainWindow_Ui.show()
    app.exec_()
